package com.sr.service.impl;

import com.sr.dao.PermissionDao;
import com.sr.dao.RolePermissionDao;
import com.sr.enums.ResponseCode;
import com.sr.exception.BusinessException;
import com.sr.ibase.impl.BaseServiceImpl;
import com.sr.pojo.SysPermission;
import com.sr.pojo.SysRolePermission;
import com.sr.service.IPermissionService;
import com.sr.util.ToolUtil;
import com.sr.vo.req.PermissionRespNodeTreeVo;
import com.sr.vo.resp.PermissionRespNodeVo;
import io.micrometer.core.instrument.util.StringUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author xiaochi
 * @date 2022/5/2 21:07
 * @desc PermissionServiceImpl
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor = @__)
public class PermissionServiceImpl extends BaseServiceImpl<SysPermission> implements IPermissionService {

    private final PermissionDao permissionDao;
    private RolePermissionDao rolePermissionDao;

    /**
     * 根据用户id查询资源
     * @param userId
     * @return
     */
    @Override
    public List<SysPermission> permissionListByUserId(String userId) {
        return permissionDao.getPermissionByUserId(userId);
    }

    /**
     * 查询所有权限列表（树形表格结果数据展示），表格列表时展示
     * 树形表格结果数据组装
     * @return
     */
    @Override
    public List<SysPermission> selectAllList() {
        List<SysPermission> sysPermissions = this.findByWhere(SysPermission.builder().deleted(1).build());
        if (!sysPermissions.isEmpty()){
            for (SysPermission sysPermission : sysPermissions){
                for (SysPermission permission : sysPermissions){
                    if(StringUtils.isNotBlank(sysPermission.getPid()) && StringUtils.isNotBlank(permission.getId()) && Objects.equals(sysPermission.getPid(),permission.getId())){
                        sysPermission.setPidName(permission.getName());
                        break;
                    }
                }
            }
        }
        return sysPermissions;
    }

    /**
     * 添加/编辑权限的上级选择权限树结构展示（递归），不需要展示到按钮
     * @return
     */
    @Override
    public List<PermissionRespNodeTreeVo> selectAllMenuByTree() {
        // 设置一个最顶级的吗，默认选项
        List<SysPermission> list = this.findAll();
        List<PermissionRespNodeTreeVo> result = new ArrayList<>();
        PermissionRespNodeTreeVo respNodeVoDefault = new PermissionRespNodeTreeVo();
        respNodeVoDefault.setId("0");
        respNodeVoDefault.setTitle("顶级菜单");
        respNodeVoDefault.setLevel(0);
        result.add(respNodeVoDefault);
        result.addAll(setPermissionLevelTree(list,String.valueOf(0),1));
        return result;
    }
    // 递归设置级别，用于权限列表 添加/编辑 所属菜单树结构数据
    private List<PermissionRespNodeTreeVo> setPermissionLevelTree(List<SysPermission> permissions,String parentId,int level){
        List<PermissionRespNodeTreeVo> list = new ArrayList<>();
        for (SysPermission permission : permissions){
            if (permission.getType().intValue() != 3 && permission.getPid().equals(parentId)){
                PermissionRespNodeTreeVo respNodeVo = new PermissionRespNodeTreeVo();
                respNodeVo.setId(permission.getId());
                respNodeVo.setTitle(permission.getTitle());
                respNodeVo.setLevel(level);
                list.add(respNodeVo);
                list.addAll(setPermissionLevelTree(permissions,permission.getId(),level+1));
            }
        }
        return list;
    }

    /**
     * 获取所有权限（包括按钮），角色添加/编辑/分配权限时用到的结结构数据
     * @return
     */
    @Override
    public List<PermissionRespNodeVo> selectAllTree() {
        return this.getTree(this.findByWhere(SysPermission.builder().deleted(1).build()),false);
    }

    /**
     * 递归筛选权限菜单
     * @param sysPermissions
     * @return
     */
    @Override
    public List<PermissionRespNodeVo> permissionTreeListMenuFilter(List<SysPermission> sysPermissions) {
        return this.getTree(sysPermissions,false);
    }

    /** 目录1；菜单2；按钮3
     * type=true 递归遍历到菜单
     * type=false 递归遍历到按钮
     * @param permissionList 用户拥有的权限列表数据
     * @param type 是否遍历到菜单，不包括按钮,true遍历按钮，false遍历菜单与按钮
     * @return
     */
    private List<PermissionRespNodeVo> getTree(List<SysPermission> permissionList,boolean type) {
        // 无父级 pid 默认 0
        return this._getTree(permissionList,"0",type);
    }

    private List<PermissionRespNodeVo> _getTree(List<SysPermission> permissionList,String pid,boolean type) {
        List<PermissionRespNodeVo> list = new ArrayList<>();
        if (permissionList == null || permissionList.isEmpty()){
            return list;
        }
        for (SysPermission permission : permissionList){
            if (Objects.equals(permission.getPid(),pid)){
                // 遍历到按钮 与 不遍历到按钮 都会执行
                if (!type || permission.getType() != 3){
                    PermissionRespNodeVo respNodeVo = ToolUtil.copy(permission, PermissionRespNodeVo.class);
                    respNodeVo.setPath(permission.getUrl());
                    respNodeVo.setMenu(permission.getType()!=3);
                    respNodeVo.setChildren(_getTree(permissionList,permission.getId(),type));
                    list.add(respNodeVo);
                }
            }
        }
        return list;
    }

    //-------------------------------------------------------------------------

    /**
     * 新增权限
     * @param sysPermission
     * @return
     */
    @Override
    public int addPermission(SysPermission sysPermission) {
        verifyForm(sysPermission);
        return this.insert(sysPermission);
    }

    /**
     * 更新权限
     * @param sysPermission
     * @return
     */
    @Override
    public int updatePermission(SysPermission sysPermission) {
        // 1.验证表单数据
        verifyForm(sysPermission);
        SysPermission permission = permissionDao.selectByPrimaryKey(sysPermission.getId());
        if (permission == null){
            log.error("传入的id在数据库中不存在,{}",sysPermission);
            throw new BusinessException(ResponseCode.DATA_ERROR);
        }
        // 2.验证 所属菜单是否发生了变化
        if (permission.getPid().equals(sysPermission.getId())){
            // 目录 菜单 按钮，如 菜单有子级按钮，则不能吧当前菜单更新为按钮类型
            // 所属菜单发生了变化要校验该权限是否存在子集
            int resultCount = permissionDao.selectChild(sysPermission.getId());// 通过 id 查询是否有子级
            if (resultCount > 0){
                throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_UPDATE);
            }
        }
        // 3.更新菜单信息
        return this.updateById(sysPermission);
    }

    /**
     * 删除权限
     * @param permissionId
     * @return
     */
    @Override
    public int deletedPermission(String permissionId) {
        SysPermission sysPermission = this.findOne(permissionId);
        if (sysPermission == null){
            log.error("传入的id在数据库中不存在,{}",sysPermission);
            throw new BusinessException(ResponseCode.DATA_ERROR);
        }
        //判断是否有子集关联，有则不能删除
        int resultCount = permissionDao.selectChild(permissionId);
        if (resultCount > 0){
            throw new BusinessException(ResponseCode.ROLE_PERMISSION_RELATION);
        }
        //通过权限id删除相关角色和该菜单权限的关联表信息
        rolePermissionDao.delete(SysRolePermission.builder().permissionId(permissionId).build());
        // 删除权限菜单表
        sysPermission.setDeleted(0);
        sysPermission.setUpdateTime(new Date());
        return this.updateById(sysPermission);
    }

    // 权限添加 / 编辑 验证参数
    private void verifyForm(SysPermission permissionReqVo){
        // 默认顶级 无父级 pid 默认 0
        //操作后的菜单类型是目录的时候 父级必须为目录
        //操作后的菜单类型是菜单的时候，父类必须为目录类型
        //操作后的菜单类型是按钮的时候 父类必须为菜单类型
        Integer type = permissionReqVo.getType();
        String pid = permissionReqVo.getPid();
        if (null != type && StringUtils.isNotBlank(pid)){
            SysPermission permission = permissionDao.selectByPrimaryKey(pid);
            if (type == 1){
                if (permission != null && permission.getType() > 1){// 父级 只能为 无父级/目录类型  0 / 1
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_CATALOG_ERROR);
                }
            }else if (type == 2) {// 父级 只能为目录类型 1
                if ("0".equals(pid) || (permission != null && permission.getType() != 1)){// 父级 只能为目录类型 1
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_MENU_ERROR);
                }
                if (StringUtils.isBlank(permissionReqVo.getUrl())){
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
            }else if (type == 3) {// 父级 只能为菜单类型 2
                if ("0".equals(pid) || (permission != null && permission.getType() != 2)){
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_BTN_ERROR);
                }
                if(StringUtils.isEmpty(permissionReqVo.getPerms())){
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_URL_PERMS_NULL);
                }
                if(StringUtils.isEmpty(permissionReqVo.getUrl())){
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_URL_NOT_NULL);
                }
                if(StringUtils.isEmpty(permissionReqVo.getMethod())){
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_URL_METHOD_NULL);
                }
                if(StringUtils.isEmpty(permissionReqVo.getCode())){
                    throw new BusinessException(ResponseCode.OPERATION_MENU_PERMISSION_URL_CODE_NULL);
                }
            }
        }else{
            throw new BusinessException(ResponseCode.DATA_ERROR);
        }
    }
}
